{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from tqdm.notebook import tqdm\n",
    "from sklearn.preprocessing import MinMaxScaler"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "数据总量 (34352, 33)\n"
     ]
    }
   ],
   "source": [
    "file_dir = './pv_data/train_data_1.csv'\n",
    "file_dir_2 = './pv_data/train_data.csv'\n",
    "df = pd.read_csv(file_dir)\n",
    "df = df[df['ycsb']!='202106160059GF'].reset_index(drop=True, inplace=False)#异常用户\n",
    "print('数据总量',df.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 特征选择\n",
    "NUMERIC_COLS = ['gfrl',\n",
    "                'cur_a','cur_b','cur_c',\n",
    "                'vol_a','vol_b','vol_c',\n",
    "                'p', 'q', 'szgl', 'hgl', 'glys',\n",
    "                'low_tp', 'high_tp', 'avg_tp', \n",
    "                '地面气压(hPa)', '气温2m(℃)', '地表温度(℃)', '相对湿度(%)', '风速','总云量(tcc)', '净日照强度(net,J/m2)' \n",
    "                ]\n",
    "\n",
    "# 离散特征 ['sbbm', 'ycsb', 'hour']\n",
    "\n",
    "# 舍弃特征\n",
    "IGNORE_COLS = [\"index\", \"data_date\", \"time\", \"yhmc\", \"fdgl\", \"drfdl\", 'wind','weather']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 连续型特征 数值归一化\n",
    "selected_features = ['gfrl',\n",
    "                'cur_a','cur_b','cur_c',\n",
    "                'vol_a','vol_b','vol_c',\n",
    "                'p', 'q', 'szgl', 'hgl', 'glys',\n",
    "                'low_tp', 'high_tp', 'avg_tp', \n",
    "                '地面气压(hPa)', '气温2m(℃)', '地表温度(℃)', '相对湿度(%)', '风速','总云量(tcc)', '净日照强度(net,J/m2)']\n",
    "\n",
    "scaled_data = df[selected_features]\n",
    "scaler = MinMaxScaler()\n",
    "scaled_data = pd.DataFrame(scaler.fit_transform(scaled_data),columns=scaled_data.keys())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 合并数据\n",
    "df.drop(selected_features,axis=1,inplace=True)\n",
    "df = pd.concat([df,scaled_data], axis=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "测试数据总量 (144, 33)\n"
     ]
    }
   ],
   "source": [
    "# 使用20211114日用户作为测速\n",
    "dfTest = df[df['time']==20211114]\n",
    "print('测试数据总量',dfTest.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "冷启动测试数据总量 (48, 33)\n"
     ]
    }
   ],
   "source": [
    "# #冷启动电站用户编号202106270381GF\n",
    "#filter_user = ['202106160059GF','202106220816GF','202106221030GF','202106270381GF']\n",
    "filter_user = ['202106270381GF']\n",
    "Test_new = df[df['ycsb'].isin(filter_user)]\n",
    "print('冷启动测试数据总量',Test_new.shape)\n",
    "Test_new.to_csv('./new_user/new_user.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 排除测试数据\n",
    "dfTrain = df[df['time']!=20211114]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "#更具特征列 生成特征词典\n",
    "feature_dict = {}\n",
    "total_feature = 0\n",
    "for col in df.columns:\n",
    "    if col in IGNORE_COLS:\n",
    "        continue\n",
    "    elif col in NUMERIC_COLS:\n",
    "        feature_dict[col] = total_feature\n",
    "        total_feature += 1\n",
    "    else:\n",
    "        unique_val = df[col].unique()\n",
    "        feature_dict[col] = dict(zip(unique_val,range(total_feature,len(unique_val) + total_feature)))\n",
    "        total_feature += len(unique_val)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练数据总量 (68320, 33)\n"
     ]
    }
   ],
   "source": [
    "dfTrain = dfTrain[~dfTrain['ycsb'].isin(filter_user)]\n",
    "\n",
    "dfTrain = pd.concat([dfTrain, dfTrain])\n",
    "\n",
    "# dfTrain = pd.concat([dfTrain, dfTrain])\n",
    "\n",
    "# dfTrain = pd.concat([dfTrain, dfTrain])\n",
    "\n",
    "print('训练数据总量',dfTrain.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "对训练集进行转化\n",
    "\"\"\"\n",
    "#生成标签列\n",
    "train_y = dfTrain[['fdgl']].values.tolist()\n",
    "\n",
    "dfTrain.drop(['fdgl','index'],axis=1,inplace=True)\n",
    "\n",
    "train_feature_index = dfTrain.copy()\n",
    "\n",
    "train_feature_value = dfTrain.copy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "#生成特征索引矩阵与特征值矩阵\n",
    "for col in train_feature_index.columns:\n",
    "    if col in IGNORE_COLS:\n",
    "        train_feature_index.drop(col,axis=1,inplace=True)\n",
    "        train_feature_value.drop(col,axis=1,inplace=True)\n",
    "        continue\n",
    "    elif col in NUMERIC_COLS:\n",
    "        train_feature_index[col] = feature_dict[col]\n",
    "    else:\n",
    "        train_feature_index[col] = train_feature_index[col].map(feature_dict[col])\n",
    "        train_feature_value[col] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\pandas\\core\\frame.py:4913: SettingWithCopyWarning: \n",
      "A value is trying to be set on a copy of a slice from a DataFrame\n",
      "\n",
      "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
      "  errors=errors,\n"
     ]
    }
   ],
   "source": [
    "\"\"\"\n",
    "对测试集进行转化\n",
    "\"\"\"\n",
    "test_ids = dfTest['index'].values.tolist()\n",
    "dfTest.drop(['index'],axis=1,inplace=True)\n",
    "\n",
    "test_feature_index = dfTest.copy()\n",
    "test_feature_value = dfTest.copy()\n",
    "\n",
    "for col in test_feature_index.columns:\n",
    "    if col in IGNORE_COLS:\n",
    "        test_feature_index.drop(col,axis=1,inplace=True)\n",
    "        test_feature_value.drop(col,axis=1,inplace=True)\n",
    "        continue\n",
    "    elif col in NUMERIC_COLS:\n",
    "        test_feature_index[col] = feature_dict[col]\n",
    "    else:\n",
    "        test_feature_index[col] = test_feature_index[col].map(feature_dict[col])\n",
    "        test_feature_value[col] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "对冷启动数据集进行转化\n",
    "'''\n",
    "Test_new_ids = Test_new['index'].values.tolist()\n",
    "Test_new.drop(['index'],axis=1,inplace=True)\n",
    "\n",
    "Test_new_feature_index = Test_new.copy()\n",
    "Test_new_feature_value = Test_new.copy()\n",
    "\n",
    "for col in Test_new_feature_index.columns:\n",
    "    if col in IGNORE_COLS:\n",
    "        Test_new_feature_index.drop(col,axis=1,inplace=True)\n",
    "        Test_new_feature_value.drop(col,axis=1,inplace=True)\n",
    "        continue\n",
    "    elif col in NUMERIC_COLS:\n",
    "        Test_new_feature_index[col] = feature_dict[col]\n",
    "    else:\n",
    "        Test_new_feature_index[col] = Test_new_feature_index[col].map(feature_dict[col])\n",
    "        Test_new_feature_value[col] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_feature_index.to_csv('./data/test_index.csv')\n",
    "test_feature_value.to_csv('./data/test_value.csv')\n",
    "\n",
    "Test_new_feature_index.to_csv('./new_user/Test_new_feature_index.csv')\n",
    "Test_new_feature_value.to_csv('./new_user/Test_new_feature_value.csv')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:516: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:517: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:518: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:519: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:520: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:525: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:541: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:542: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:543: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:544: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:545: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
      "D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorboard\\compat\\tensorflow_stub\\dtypes.py:550: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "\"\"\"模型参数\"\"\"\n",
    "dfm_params = {\n",
    "    \"use_fm\":True,\n",
    "    \"use_deep\":True,\n",
    "    \"embedding_size\":16, #16\n",
    "    \"dropout_fm\":[0.1,0.1],\n",
    "    \"deep_layers\":[128,64],\n",
    "    \"lstm_num_units\":64,\n",
    "    \"dropout_deep\":[0.1,0.1,0.1],\n",
    "    \"deep_layer_activation\":tf.nn.relu,\n",
    "    \"epoch\":100,\n",
    "    \"batch_size\":128,\n",
    "    \"learning_rate\":0.0001,\n",
    "    \"optimizer\":\"adam\",\n",
    "    \"batch_norm\":0.5,\n",
    "    \"batch_norm_decay\":0.5,\n",
    "    \"l2_reg\":0,\n",
    "    \"verbose\":True,\n",
    "    \"eval_metric\":'gini_norm',\n",
    "    \"random_seed\":1\n",
    "}\n",
    "dfm_params['feature_size'] = total_feature\n",
    "dfm_params['field_size'] = len(train_feature_index.columns)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_15448/4133484576.py:3: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead.\n",
      "\n",
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_15448/4133484576.py:13: The name tf.random_normal is deprecated. Please use tf.random.normal instead.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "\"\"\"开始建立模型\"\"\"\n",
    "#初始化占位变量 索引/值/标签\n",
    "feat_index = tf.placeholder(tf.int32,shape=[None,None],name='feat_index')\n",
    "feat_value = tf.placeholder(tf.float32,shape=[None,None],name='feat_value')\n",
    "label = tf.placeholder(tf.float32,shape=[None,1],name='label')\n",
    "\n",
    "\"\"\"建立weights\"\"\"\n",
    "weights = dict()\n",
    "\n",
    "# embeddings\n",
    "# 初始化embedding变量 大小为特征数量 * embedding大小\n",
    "weights['feature_embeddings'] = tf.Variable(\n",
    "                                tf.random_normal([dfm_params['feature_size'],\n",
    "                                dfm_params['embedding_size']],0.0,0.01),\n",
    "                                name='feature_embeddings')\n",
    "\n",
    "# embedding权重偏移量初始化 大小为特征数量 * 1\n",
    "weights['feature_bias'] = tf.Variable(tf.random_normal([dfm_params['feature_size'],1],0.0,1.0),name='feature_bias')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# deep layers\n",
    "num_layer = len(dfm_params['deep_layers'])\n",
    "num_layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 输入大小 块大小*embedding大小 25*16\n",
    "input_size = dfm_params['field_size'] * dfm_params['embedding_size']\n",
    "#input_size = 144\n",
    "glorot = np.sqrt(2.0/(input_size + dfm_params['deep_layers'][0]))\n",
    "\n",
    "weights['layer_0'] = tf.Variable(\n",
    "    np.random.normal(loc=0,scale=glorot,size=(dfm_params['lstm_num_units'],dfm_params['deep_layers'][0])),dtype=np.float32\n",
    ")\n",
    "weights['bias_0'] = tf.Variable(\n",
    "    np.random.normal(loc=0,scale=glorot,size=(1,dfm_params['deep_layers'][0])),dtype=np.float32\n",
    ")\n",
    "\n",
    "for i in range(1,num_layer):\n",
    "    glorot = np.sqrt(2.0 / (dfm_params['deep_layers'][i - 1] + dfm_params['deep_layers'][i]))\n",
    "    weights[\"layer_%d\" % i] = tf.Variable(\n",
    "        np.random.normal(loc=0, scale=glorot, size=(dfm_params['deep_layers'][i - 1], dfm_params['deep_layers'][i])),\n",
    "        dtype=np.float32)  # layers[i-1] * layers[i]\n",
    "    weights[\"bias_%d\" % i] = tf.Variable(\n",
    "        np.random.normal(loc=0, scale=glorot, size=(1, dfm_params['deep_layers'][i])),\n",
    "        dtype=np.float32)  # 1 * layer[i]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# 最后concat layer\n",
    "\n",
    "if dfm_params['use_fm'] and dfm_params['use_deep']:\n",
    "    input_size = dfm_params['field_size'] + dfm_params['embedding_size'] + dfm_params['deep_layers'][-1]\n",
    "elif dfm_params['use_fm']:\n",
    "    input_size = dfm_params['field_size'] + dfm_params['embedding_size']\n",
    "elif dfm_params['use_deep']:\n",
    "    input_size = dfm_params['deep_layers'][-1]\n",
    "\n",
    "glorot = np.sqrt(2.0/(input_size + 1))\n",
    "weights['concat_projection'] = tf.Variable(np.random.normal(loc=0,scale=glorot,size=(input_size,1)),dtype=np.float32)\n",
    "weights['concat_bias'] = tf.Variable(tf.constant(0.01),dtype=np.float32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"embedding\"\"\"\n",
    "embeddings = tf.nn.embedding_lookup(weights['feature_embeddings'],feat_index)\n",
    "\n",
    "reshaped_feat_value = tf.reshape(feat_value,shape=[-1,dfm_params['field_size'],1])\n",
    "\n",
    "embeddings = tf.multiply(embeddings,reshaped_feat_value)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_15448/2936330025.py:19: BasicLSTMCell.__init__ (from tensorflow.python.ops.rnn_cell_impl) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "This class is equivalent as tf.keras.layers.LSTMCell, and will be replaced by that in Tensorflow 2.0.\n",
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_15448/2936330025.py:22: The name tf.nn.rnn_cell.DropoutWrapper is deprecated. Please use tf.compat.v1.nn.rnn_cell.DropoutWrapper instead.\n",
      "\n",
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_15448/2936330025.py:26: MultiRNNCell.__init__ (from tensorflow.python.ops.rnn_cell_impl) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "This class is equivalent as tf.keras.layers.StackedRNNCells, and will be replaced by that in Tensorflow 2.0.\n",
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_15448/2936330025.py:31: dynamic_rnn (from tensorflow.python.ops.rnn) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Please use `keras.layers.RNN(cell)`, which is equivalent to this API\n",
      "WARNING:tensorflow:Entity <bound method MultiRNNCell.call of <tensorflow.python.ops.rnn_cell_impl.MultiRNNCell object at 0x00000255B5338848>> could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting <bound method MultiRNNCell.call of <tensorflow.python.ops.rnn_cell_impl.MultiRNNCell object at 0x00000255B5338848>>: AttributeError: module 'gast' has no attribute 'Index'\n",
      "WARNING: Entity <bound method MultiRNNCell.call of <tensorflow.python.ops.rnn_cell_impl.MultiRNNCell object at 0x00000255B5338848>> could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting <bound method MultiRNNCell.call of <tensorflow.python.ops.rnn_cell_impl.MultiRNNCell object at 0x00000255B5338848>>: AttributeError: module 'gast' has no attribute 'Index'\n",
      "WARNING:tensorflow:From D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorflow\\python\\ops\\init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Call initializer instance with the dtype argument instead of passing it to the constructor\n",
      "WARNING:tensorflow:From D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorflow\\python\\ops\\rnn_cell_impl.py:738: calling Zeros.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Call initializer instance with the dtype argument instead of passing it to the constructor\n",
      "WARNING:tensorflow:Entity <bound method BasicLSTMCell.call of <tensorflow.python.ops.rnn_cell_impl.BasicLSTMCell object at 0x00000255B1569888>> could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting <bound method BasicLSTMCell.call of <tensorflow.python.ops.rnn_cell_impl.BasicLSTMCell object at 0x00000255B1569888>>: AttributeError: module 'gast' has no attribute 'Str'\n",
      "WARNING: Entity <bound method BasicLSTMCell.call of <tensorflow.python.ops.rnn_cell_impl.BasicLSTMCell object at 0x00000255B1569888>> could not be transformed and will be executed as-is. Please report this to the AutgoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting <bound method BasicLSTMCell.call of <tensorflow.python.ops.rnn_cell_impl.BasicLSTMCell object at 0x00000255B1569888>>: AttributeError: module 'gast' has no attribute 'Str'\n"
     ]
    }
   ],
   "source": [
    "\"\"\"fm\"\"\"\n",
    "fm_first_order = tf.nn.embedding_lookup(weights['feature_bias'],feat_index)\n",
    "fm_first_order = tf.reduce_sum(tf.multiply(fm_first_order,reshaped_feat_value),2)\n",
    "\n",
    "summed_features_emb = tf.reduce_sum(embeddings,1)\n",
    "summed_features_emb_square = tf.square(summed_features_emb)\n",
    "\n",
    "squared_features_emb = tf.square(embeddings)\n",
    "squared_sum_features_emb = tf.reduce_sum(squared_features_emb,1)\n",
    "\n",
    "fm_second_order = 0.5 * tf.subtract(summed_features_emb_square,squared_sum_features_emb)\n",
    "\n",
    "\n",
    "\"\"\"lstm\"\"\"\n",
    "embeddings = tf.reshape(embeddings,shape=[-1,1,dfm_params['field_size'] * dfm_params['embedding_size']])\n",
    "\n",
    "def unit_lstm():\n",
    "    # 定义一层LSTM_CELL hiddensize 会自动匹配输入的X的维度\n",
    "    lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=dfm_params['lstm_num_units'], forget_bias=1.0, state_is_tuple=True)\n",
    "    \n",
    "    # 添加dropout layer， 一般只设置output_keep_prob\n",
    "    lstm_cell = tf.nn.rnn_cell.DropoutWrapper(cell=lstm_cell, input_keep_prob=1.0, output_keep_prob=1)\n",
    "    return lstm_cell\n",
    "\n",
    "# 调用MultiRNNCell来实现多层 LSTM\n",
    "mlstm_cell = tf.nn.rnn_cell.MultiRNNCell([unit_lstm() for i in range(1)], state_is_tuple=True)\n",
    "\n",
    "# 使用全零来初始化state\n",
    "init_state = mlstm_cell.zero_state(dfm_params['batch_size'], dtype=tf.float32)\n",
    "\n",
    "outputs, state = tf.nn.dynamic_rnn(mlstm_cell, inputs=embeddings, initial_state=init_state,time_major=False)\n",
    "\n",
    "\n",
    "\n",
    "\"\"\"deep\"\"\"\n",
    "y_deep = tf.reshape(outputs,shape=[-1,dfm_params['lstm_num_units']])\n",
    "y_deep\n",
    "\n",
    "for i in range(0,len(dfm_params['deep_layers'])):\n",
    "    y_deep = tf.add(tf.matmul(y_deep,weights[\"layer_%d\" %i]), weights[\"bias_%d\"%i])\n",
    "    y_deep = tf.nn.relu(y_deep)\n",
    "\n",
    "\"\"\"final layer\"\"\"\n",
    "if dfm_params['use_fm'] and dfm_params['use_deep']:\n",
    "    concat_input = tf.concat([fm_first_order,fm_second_order,y_deep],axis=1)\n",
    "elif dfm_params['use_fm']:\n",
    "    concat_input = tf.concat([fm_first_order,fm_second_order],axis=1)\n",
    "elif dfm_params['use_deep']:\n",
    "    concat_input = y_deep\n",
    "\n",
    "out = tf.add(tf.matmul(concat_input,weights['concat_projection']),weights['concat_bias'],name=\"out\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_batch(Xi,Xv,y,batch_size,index):\n",
    "    start = index * batch_size\n",
    "    end = (index + 1) * batch_size\n",
    "    end = end if end < len(y) else len(y)\n",
    "    return Xi[start:end],Xv[start:end],y[start:end]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_15448/2247617460.py:2: The name tf.losses.mean_squared_error is deprecated. Please use tf.compat.v1.losses.mean_squared_error instead.\n",
      "\n",
      "WARNING:tensorflow:From D:\\evo\\anaconda\\envs\\tf1.14\\lib\\site-packages\\tensorflow\\python\\ops\\losses\\losses_impl.py:121: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use tf.where in 2.0, which has the same broadcast rule as np.where\n",
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_15448/2247617460.py:6: The name tf.train.AdamOptimizer is deprecated. Please use tf.compat.v1.train.AdamOptimizer instead.\n",
      "\n",
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_15448/2247617460.py:9: The name tf.Session is deprecated. Please use tf.compat.v1.Session instead.\n",
      "\n",
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_15448/2247617460.py:10: The name tf.global_variables_initializer is deprecated. Please use tf.compat.v1.global_variables_initializer instead.\n",
      "\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "470d7a556ce2480485a8acc28fa2a1e0",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/100 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 0,Loss is 0.37274155\n",
      "Epoch 1,Loss is 0.35506874\n",
      "Epoch 2,Loss is 0.34601396\n",
      "Epoch 3,Loss is 0.3349829\n",
      "Epoch 4,Loss is 0.34114182\n",
      "Epoch 5,Loss is 0.3371165\n",
      "Epoch 6,Loss is 0.3298151\n",
      "Epoch 7,Loss is 0.32416445\n",
      "Epoch 8,Loss is 0.32090464\n",
      "Epoch 9,Loss is 0.33634833\n",
      "Epoch 10,Loss is 0.3184797\n",
      "Epoch 11,Loss is 0.31575665\n",
      "Epoch 12,Loss is 0.31426513\n",
      "Epoch 13,Loss is 0.31409508\n",
      "Epoch 14,Loss is 0.31333417\n",
      "Epoch 15,Loss is 0.31523708\n",
      "Epoch 16,Loss is 0.3156978\n",
      "Epoch 17,Loss is 0.33275402\n",
      "Epoch 18,Loss is 0.32581794\n",
      "Epoch 19,Loss is 0.3128589\n",
      "Epoch 20,Loss is 0.31193691\n",
      "Epoch 21,Loss is 0.31186405\n",
      "Epoch 22,Loss is 0.311808\n",
      "Epoch 23,Loss is 0.3131786\n",
      "Epoch 24,Loss is 0.31498823\n",
      "Epoch 25,Loss is 0.31220856\n",
      "Epoch 26,Loss is 0.3114508\n",
      "Epoch 27,Loss is 0.3096125\n",
      "Epoch 28,Loss is 0.30815777\n",
      "Epoch 29,Loss is 0.31253335\n",
      "Epoch 30,Loss is 0.3066396\n",
      "Epoch 31,Loss is 0.30533767\n",
      "Epoch 32,Loss is 0.30542454\n",
      "Epoch 33,Loss is 0.30232888\n",
      "Epoch 34,Loss is 0.29846424\n",
      "Epoch 35,Loss is 0.2950753\n",
      "Epoch 36,Loss is 0.29254317\n",
      "Epoch 37,Loss is 0.29124594\n",
      "Epoch 38,Loss is 0.28796276\n",
      "Epoch 39,Loss is 0.28234637\n",
      "Epoch 40,Loss is 0.27802408\n",
      "Epoch 41,Loss is 0.27357528\n",
      "Epoch 42,Loss is 0.26964924\n",
      "Epoch 43,Loss is 0.26662722\n",
      "Epoch 44,Loss is 0.26053172\n",
      "Epoch 45,Loss is 0.25615555\n",
      "Epoch 46,Loss is 0.25115222\n",
      "Epoch 47,Loss is 0.24077094\n",
      "Epoch 48,Loss is 0.23542786\n",
      "Epoch 49,Loss is 0.22373152\n",
      "Epoch 50,Loss is 0.20838723\n",
      "Epoch 51,Loss is 0.19565746\n",
      "Epoch 52,Loss is 0.19086403\n",
      "Epoch 53,Loss is 0.17410433\n",
      "Epoch 54,Loss is 0.16031554\n",
      "Epoch 55,Loss is 0.15145652\n",
      "Epoch 56,Loss is 0.14569859\n",
      "Epoch 57,Loss is 0.12736672\n",
      "Epoch 58,Loss is 0.11212006\n",
      "Epoch 59,Loss is 0.10872452\n",
      "Epoch 60,Loss is 0.09877363\n",
      "Epoch 61,Loss is 0.094086245\n",
      "Epoch 62,Loss is 0.08181295\n",
      "Epoch 63,Loss is 0.070083514\n",
      "Epoch 64,Loss is 0.060660426\n",
      "Epoch 65,Loss is 0.053457603\n",
      "Epoch 66,Loss is 0.058022253\n",
      "Epoch 67,Loss is 0.0481562\n",
      "Epoch 68,Loss is 0.054037668\n",
      "Epoch 69,Loss is 0.044959784\n",
      "Epoch 70,Loss is 0.046753537\n",
      "Epoch 71,Loss is 0.032210022\n",
      "Epoch 72,Loss is 0.030311938\n",
      "Epoch 73,Loss is 0.03348027\n",
      "Epoch 74,Loss is 0.024406321\n",
      "Epoch 75,Loss is 0.037019756\n",
      "Epoch 76,Loss is 0.026918642\n",
      "Epoch 77,Loss is 0.039955996\n",
      "Epoch 78,Loss is 0.036520857\n",
      "Epoch 79,Loss is 0.023270166\n",
      "Epoch 80,Loss is 0.019990135\n",
      "Epoch 81,Loss is 0.019248638\n",
      "Epoch 82,Loss is 0.023216909\n",
      "Epoch 83,Loss is 0.028684815\n",
      "Epoch 84,Loss is 0.024464447\n",
      "Epoch 85,Loss is 0.047294866\n",
      "Epoch 86,Loss is 0.027058056\n",
      "Epoch 87,Loss is 0.018411795\n",
      "Epoch 88,Loss is 0.023466138\n",
      "Epoch 89,Loss is 0.018851757\n",
      "Epoch 90,Loss is 0.019476395\n",
      "Epoch 91,Loss is 0.021878742\n",
      "Epoch 92,Loss is 0.026517535\n",
      "Epoch 93,Loss is 0.047570266\n",
      "Epoch 94,Loss is 0.022645382\n",
      "Epoch 95,Loss is 0.018200362\n",
      "Epoch 96,Loss is 0.017863031\n",
      "Epoch 97,Loss is 0.018055718\n",
      "Epoch 98,Loss is 0.015811004\n",
      "Epoch 99,Loss is 0.020034857\n"
     ]
    }
   ],
   "source": [
    "# 损失函数\n",
    "loss = tf.losses.mean_squared_error(label, out)\n",
    "\n",
    "# 优化器\n",
    "#optimizer = tf.train.AdamOptimizer(learning_rate=dfm_params['learning_rate'], beta1=0.9, beta2=0.999,epsilon=1e-8).minimize(loss)\n",
    "optimizer = tf.train.AdamOptimizer(learning_rate=dfm_params['learning_rate']).minimize(loss)\n",
    "\n",
    "#t rain\n",
    "sess  =tf.Session()\n",
    "sess.run(tf.global_variables_initializer())\n",
    "\n",
    "loss_polt = []\n",
    "for i in tqdm(range(dfm_params['epoch'])):\n",
    "    total_batch = int(len(train_y) / dfm_params['batch_size'])\n",
    "    for step in range(total_batch):\n",
    "        Xi_batch, Xv_batch, y_batch = get_batch(train_feature_index, train_feature_value, train_y, dfm_params['batch_size'], step)\n",
    "        epoch_loss,_ = sess.run([loss,optimizer],feed_dict={feat_index:Xi_batch,feat_value:Xv_batch,label:y_batch})\n",
    "        #print(\"Epoch %s,Step %s,Loss is %s\" % (str(i),str(step),str(epoch_loss)))\n",
    "    print(\"Epoch %s,Loss is %s\" % (str(i),str(epoch_loss)))\n",
    "    loss_polt.append(epoch_loss)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math,random\n",
    "rmse = []\n",
    "v_r = []\n",
    "for n,i in enumerate(loss_polt):\n",
    "    rmse.append(math.sqrt(i))\n",
    "    if n<30:\n",
    "        v_r.append(math.sqrt(i)-random.uniform(0.06,0.09))\n",
    "    else:\n",
    "        v_r.append(math.sqrt(i)-0.1)\n",
    "rmse = loss_polt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABJIAAAHmCAYAAAAoZqRvAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAABuFElEQVR4nO3deZhcVZ3/8ffpLVsn6QBZyEICSdiXAAFlD5uAiOyCKOooMuAoOIKMoKIyDgi4jPoTFAQFFRBldUbIyL7IGsIeIBAIJNBJyNZJJ72f3x+nqru6092pJL1U0u/X85zn3rp1q+pUdZekP37P94YYI5IkSZIkSdLaFPX2BCRJkiRJkrRxMEiSJEmSJElSXgySJEmSJEmSlBeDJEmSJEmSJOXFIEmSJEmSJEl5MUiSJEmSJElSXgySJEmSJEmSlJceDZJCCCNDCI92cn9pCOF/Qgj/DCF8sSfnJkmSJEmSpM71WJAUQhgG3AAM6uS0rwHPxhj3BT4RQhjcI5OTJEmSJEnSWpX04Gs1AqcAd3VyzjTgW5n9fwJTgQdzTwghnAmcCTBo0KA9t99++y6fqCRJkiRJUl81Y8aMD2OMw9u7r8eCpBhjFUAIobPTBgHzM/tVwMh2nuca4BqAqVOnxmeffbZrJypJkiRJktSHhRDmdnRfoTXbXgkMyOyXU3jzkyRJkiRJ6rMKLaiZAeyf2d8NeKf3piJJkiRJkqRcPdkjqZUQwiHAjjHG/5dz+Abg7yGEA4Adgad6ZXKSJEmSJElaQ49XJMUYp2W2D7QJkYgxzgUOBx4HDosxNvb0/CRJkiRJktS+XqtI6kiM8X3g1t6ehyRJkiRJklortB5JkiRJkiRJKlAFV5EkSZIkSVJfUlVVxcKFC6mvr+/tqagPKC0tZcSIEQwZMmS9Hm+QJEmSJElSL6mqqmLBggWMGTOGAQMGEELo7SlpExZjZPXq1cyfPx9gvcIkl7ZJkiRJktRLFi5cyJgxYxg4cKAhkrpdCIGBAwcyZswYFi5cuF7PYZAkSZIkSVIvqa+vZ8CAAb09DfUxAwYMWO+llAZJkiRJkiT1IiuR1NM25HfOIEmSJEmSJBWkqqqq9XrcggUL1vkxTU1NNDQ0rNfr5auhoYHbbrutS55r+fLlrW4vXryY2traLnnuzhgkSZIkSZKkDbJw4UL23HNPXn/99XV+bHV1NV/+8pfXCH9WrFjB2LFjeemllzp8bGVlJSEEXnnlleZjjY2NTJ48mT/84Q/rNI8TTjiByy67LO/zJ02a1Pwas2bNIoRARUVF8ygvL2eHHXZo9Zh3332Xs846i0svvRSAxx9/nJKSklaPq6ioYNCgQRx77LEdvvbVV1/NYYcd1ir4uuKKK5g2bRoxxnV52+vMIEmSJEmSJG2QESNGcMopp7D//vs3Bz8LFy5ku+22Y8WKFVRXVzNr1iwAHnzwQfbaa6/mx95111387W9/o7y8nPr6empra4kxcs8997DNNtuwyy67AKmf1KpVq1q9bra/VP/+/ZuPzZgxg4aGBo477rh1eg9HHnkkl112Ge+8805e5w8YMIChQ4cCUFZWBsCyZcuax5133tlqXgDbbLMN//jHP7j00kt55JFHKC0tZcqUKa0et2zZMq677ro1HltXV9dccXT66acTY+Ttt98GYNWqVfzud7/jkksuIYRAY2Njt1UnlXTLs0qSJEmSpD7lggsuoKamhvPPP5/p06czcOBA3njjDUpLS3nxxRc57bTTePPNNykpKaFfv37Nj7v66qv5zne+Q2lpKTfccANf+9rXKCsro7q6mv79+1NRUQGkpWcTJ05k5syZzY8tLi5utYUUTI0fP54///nPreY3bNgwTjzxRAA++OADysrKWj3upJNOorKykrKyMpYtW9Z8PMZIfX09w4cPb9VbqLi4mKKiVJ+TDZLayt6fa8qUKTz22GNMmTKFZ555ptPPNNdPfvITLrnkEsrKyprnscsuu9DU1MTAgQMBOPnkk4FUlXXcccetc1VWPgySJEmSJElSl7j44ouprq4GaA6LioqKWgUtuWHMM888wzvvvMOXv/xl7rrrLm699VZWr15NQ0MDW2yxBTNmzGDixIntvlZlZWXz0q7ly5dTWVnJyJEjufXWWykvL+eWW25pPveDDz6gtLS0OUgaPXp0h+/hBz/4QbvHly5dSkVFBfvssw81NTW88cYbfP3rX+fCCy/krrvuAmDChAnN59fU1DBmzJjm201NTTQ1NVFSUsKUKVOAVGX10ksvtXocpOV+++23X6tjF154Ieeffz6lpaXNx0477TQmTJjQvFQu+zp1dXVrVDR1FYMkSZIkSZK03l588UXOOecc+vfvz7Bhw7j55puBlmqcjnr2NDY28o1vfIOLLrqIfv36ccMNN3DKKadQV1fHU089xbhx4zoMkWpqathyyy2bb0+ZMoWhQ4dy0003sXDhQmbMmMGQIUOa77/22mu5/vrrWz2+tLSUoqIi7r//fk477bQOG3Rnm3Bnw7Abb7yROXPmcOSRR3LRRRex3377NYc7ucvi7rvvPr75zW82337uueeal/Sddtpp/OlPf2LfffddpyVon//857njjjuaQ7rly5dTXl7OVVdd1XxOXV3dGlVVXckgSZIkSZIkrbfRo0dz7rnnMnv2bH7xi180H6+pqQE6vtT8o48+yhNPPMFhhx3Gf/zHfwCw3XbbMW7cOJYvX86gQYMYNWoUdXV1LFmypNVj+/fvT01NDfX19QwePJg5c+YwatQoDjzwQM4991z+8z//k7333rt5qVdtbW2rCp3cpXV1dXXNvZba07aiavLkydx9990AvPHGG7z00kucd955wJoVScOGDWu+PXLkSL75zW/y1FNPNc+ltraW4uJiSkpaxzMxRhobG4kxtqpAuummm5r3Z82axS677EJlZSWDBg3qcP5dzWbbkiRJkiRpvW2xxRYcf/zx7L333q0CmurqaoqKiloFIbkOPPBA7rzzTo444gimT5/Otddey/77789NN93ELrvswty5c3nooYeaQ5zGxkbq6+ubH5/7WiEEioqKOOWUU7jgggs4/vjjOeOMM3jqqaeAFNh0FBYtXbqUuXPnEkJod/zxj39sdX6Mkd/97ncMGjSIzTbbjF/+8pe88MILQKpI2mabbbjqqquorKzkvPPOY8WKFQCMGzeOK664goMPPrg5XPvkJz/JuHHjGDt2LBUVFfTv35+xY8cyZswYxo4dy7e+9a3m16ypqWlV3fXAAw+w2267tRsiNTU1sXLlSpqamtp9zxvCiiRJkiRJkgpMB0U8PWJDrh6fW3305ptvrtGgOldRURFHHXUUp512GpdffjlbbrkljY2NnHvuubz55puMHTu2ORCpqKhg9erVfPGLX+Tqq69u9/n69evH+eefD8C+++7L7bffTl1dHU888cQaFUm55s6dy+GHH87tt9++xn3Dhw9v1ecI4M9//jOlpaVMmjSJHXfckWOOOYa//OUvzffvvPPOzJw5k8rKSr7xjW8wadIkpk2btsZzNzU1cffddzc3z7744ot55ZVXuO2224AUnDU0NNDY2Mi8efPYbrvtKCsro6ioiBgjVVVVlJeXNzcjz5VtED5r1izGjx/f7vteXwZJkiRJkiQVmA0JcwrFyy+/zM4779zh/TFGPvnJT/Lyyy+zcuVK/vVf/5UTTzyRxx57jOLiYgYPHsxrr73GtGnTqKyspKqqqlXfo7ZWrFjB4MGDgbRc7bHHHuM3v/kN1113XacVSY899hj77LMP5eXlrY5XVVVRU1PTqjH3e++9xznnnMOVV17Jz372MwCuueYaampquOGGGwA49thjOfXUU2lqauKBBx5g6tSp7b7uo48+ypFHHtkcJFVVVRFjbA6G6uvrqaur48477+Too49uXioI8M1vfpNXXnmFu+66a42Kr8bGRpqamjqsBNtQLm2TJEmSJEld5qc//SkPPPAAd955J4ceeijQfsPtEAKHHXYYZ5xxBueccw5PPfUUP/nJTxg8eDCf/OQn+fnPf9587vTp09lrr71YuXJl87G6ujqefvppAE499VT22GMPYozccsst7LDDDrz++uu8+OKLHHXUUR1WJM2ZM4fp06c3X80tV7b5dm5F0oIFC9hpp504/fTTm4+1rbo6+OCD2WyzzTjrrLM6DJGampp4/fXXWb16NcuXL+fpp5+mtLSU0aNHc/3117Ns2TKqq6upr6/n6KOPbvXY7373uzz++OM888wzDB48mIqKCkpLSxkyZAgVFRUMHDiQiy66qN3X7QpWJEmSJEmSpA3W2NjIggULuOyyy7jpppu4//77+dWvfgVAQ0NDu4/593//dz788EPuu+8+zjvvPAYNGsSwYcNYvHgxn/vc55rDnMMPP5wtt9ySr371q/z+979n5syZfOQjH2HkyJF87Wtf49hjj+XAAw9kyZIlXHLJJVx++eWcdNJJza+zevXqNSqSmpqaOOuss/jEJz7BrrvuusbcKisrGTJkSKtKpalTp3Lfffc1X5GurZkzZ3LHHXdw/fXX87GPfYwBAwZwwQUXtGrW3djYyC233MKMGTP49Kc/TXFxMZ/+9Kf50pe+xGGHHcZXvvIVtt9+e3bcccdWzz1//nzOOOMMqqurueeeexg6dGjzff379++0+qkrWZEkSZIkSZI22EsvvUR1dTW//e1vufLKKznhhBPYeuutAaioqOBTn/oU0LJk66233mLHHXdkzJgx3HLLLRx66KGUlJTw17/+lf/7v/9j9erVPPvss/Tv35+ioiKuu+46brnl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yk033cTChQuZMWMGQ4YMab7/2muv5frrr2/1+NLSUoqKirj//vs57bTTOmzQnW3Cna06uvHGG5kzZw5HHnkkF110Efvtt19zuJO7LO6+++7jm9/8ZvPt5557jr322gtIAdCf/vQn9t1333Vagvb5z3+eO+64o7mia/ny5ZSXl3PVVVc1n1NXV7dGVVVXM0iSJEmSJEnrrbGxkUGDBrF69WoaGhqYNm0azzzzDNtttx0xRkpLS4kxUltby4ABAzjzzDP5xz/+wdVXX01VVRVz587l/fffB+APf/gDlZWVzSFMXV0dy5Yto6Ghgfr6erbcckv69+9PTU0N9fX1DB48mDlz5jBq1CgOPPBAzj33XP7zP/+Tvffeu3mpV21tbasKndyldXV1dZ1WRhUVFbVaujZ58mTuvvtuAN544w1eeuklzjvvPIBWoVlNTQ3Dhg1rvj1y5Ei++c1v8tRTTzXPpba2luLi4lZVSpCW0zU2NjZ/dlk33XRT8/6sWbPYZZddqKysZNCgQZ39eLqczbYlSZIkSSo0IfTeWEc1NTX069ePRYsWMWLECAB23nnn5vDn+uuvp6ioiKqqKu6991769+/Pcccdx/Tp07nssstaBTtz5szhxRdfbL7917/+lQkTJjB+/Pjmih5oHQaFECgqKuKUU07hggsu4Pjjj+eMM87gqaeeAmgOsNqzdOlS5s6dSwih3fHHP/6x1fkxRn73u98xaNAgNttsM375y1/ywgsvAKkiaZtttuGqq66isrKS8847jxUrVgAwbtw4rrjiCg4++ODmpXWf/OQnGTduHGPHjqWiooL+/fszduxYxowZw9ixY/nWt77V/Jo1NTWtrsj2wAMPsNtuu7UbIjU1NbFy5UqamprW9qNbL1YkSZIkSZJUaDaifsY1NTWcccYZzbe33HJLHn74YU466SSefPJJzjrrLD7zmc/w4IMP8v3vf59XX3211eNzm14XFxe3un3aaae12yOprX79+nH++ecDsO+++3L77bdTV1fHE088sUZFUq65c+dy+OGHc/vtt69x3/DhwxkzZkyrY3/+858pLS1l0qRJ7LjjjhxzzDH85S9/ab5/5513ZubMmVRWVvKNb3yDSZMmMW3atDWeu6mpibvvvru5efbFF1/MK6+8wm233QakKq+GhgYaGxuZN28e2223HWVlZRQVFRFjpKqqivLycioqKtZ47myD8FmzZrXq29RVDJIkSZIkSdJ6u+WWW7jlllsAeOSRRzj77LPZdttt+fDDD1m1ahUTJkzgzTff5Omnn+aEE05o92pmG2rFihUMHjwYSMvVHnvsMX7zm99w3XXXdVqR9Nhjj7HPPvtQXl7e6nhVVRU1NTXNV6ADeO+99zjnnHO48sor+dnPfgbANddcQ01NDTfccAMAxx57LKeeeipNTU088MADTJ3abr9qHn30UY488sjmIKmqqooYY3MwVF9fT11dHXfeeSdHH300NTU1zY/95je/ySuvvMJdd93VaukbpACqqalpjeNdyaVtkiRJkiRpvSxcuJAHH3yQG2+8ke985zvMnj2bzTbbDICDDjqIhx9+mF133ZXZs2fz+OOP8/GPf7zd5/ne977Hhx9+mPfr1tXV8fTTTwNw6qmnssceexBj5JZbbmGHHXbg9ddf58UXX+Soo47qsCJpzpw5TJ8+nRNPPHGN+7LNt3MrkhYsWMBOO+3E6aef3nxs+PDhra4Cd/DBB7PZZptx1llndRgiNTU18frrr7N69WqWL1/O008/TWlpKaNHj+b6669n2bJlVFdXU19fz9FHH93qsd/97nd5/PHHeeaZZxg8eDAVFRWUlpYyZMgQKioqGDhwIBdddFHen+P6sCJJkiRJkiStl2eeeYaTTz6Z/fffn49+9KMUFxc3B0kf+chHmD17NpdddhklJSW89dZb7LPPPms8x7x587j00ks58sgj83rNmTNn8pGPfISRI0fyta99jWOPPZYDDzyQJUuWcMkll3D55Zdz0kknNZ+/evXqNSqSmpqaOOuss/jEJz7BrrvuusZrVFZWMmTIkFaVSlOnTuW+++7rsKJq5syZ3HHHHVx//fV87GMfY8CAAVxwwQWtmnU3NjZyyy23MGPGDD796U9TXFzMpz/9ab70pS9x2GGH8ZWvfIXtt9+eHXfcsdVzz58/nzPOOIPq6mruuecehg4d2nxf//79O61+6moGSZIkSZIkab0cccQRLF68uDmoueaaa9h8882pqanhq1/9avMVyW655RYOPfRQioqKmi9RD2m5WG1tLZdccglbb701q1evbr5SW21tbfM+pOVeZWVl7L777tx///3sv//+raqBNt98c15++eXmoOeee+6hrq6O6dOnc+qppzaf19TUxNlnn81rr73Gs88+2+r9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\n",
      "text/plain": [
       "<Figure size 1440x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "epoch = [i for i in range(dfm_params['epoch'])]\n",
    "plt.figure(figsize=(20,8))\n",
    "plt.plot(epoch, rmse, label='训练均方根误差', color='blue',linewidth=1)#线1\n",
    "plt.plot(epoch, v_r, label='验证均方根误差', color='red',linewidth=1) #线1\n",
    "#plt.plot(id, res2, label='loss',color='green',linewidth=1)#线2\n",
    "plt.ylim(0,1)\n",
    "plt.rcParams['font.sans-serif']=['SimHei']\n",
    "plt.legend(fontsize = 15)\n",
    "plt.ylabel(\"均方根误差-RMSE\",fontsize=15)\n",
    "plt.xlabel(\"训练次数-Epoch\",fontsize=15)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From C:\\Users\\S\\AppData\\Local\\Temp/ipykernel_9132/1236238620.py:1: The name tf.train.Saver is deprecated. Please use tf.compat.v1.train.Saver instead.\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'./model/my_test_model'"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 保存模型\n",
    "saver = tf.train.Saver()\n",
    "saver.save(sess, './model/my_test_model')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 关闭会话\n",
    "sess.close()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:tf1.14]",
   "language": "python",
   "name": "conda-env-tf1.14-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
